package com.beaven.model.data.helper;

import com.beaven.model.model.db.AppDatabase;
import com.beaven.model.model.db.Group;
import com.beaven.model.model.db.GroupMember;
import com.beaven.model.model.db.Group_Table;
import com.beaven.model.model.db.Message;
import com.beaven.model.model.db.Session;
import com.raizlabs.android.dbflow.config.DatabaseDefinition;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.sql.language.SQLite;
import com.raizlabs.android.dbflow.structure.BaseModel;
import com.raizlabs.android.dbflow.structure.ModelAdapter;
import com.raizlabs.android.dbflow.structure.database.DatabaseWrapper;
import com.raizlabs.android.dbflow.structure.database.transaction.ITransaction;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * author: Beaven
 * time: 2017/5/24 11:10
 *
 * 数据库操作辅助类
 */

public class DbHelper {

  private static class Instance {
    private static final DbHelper dbHelper = new DbHelper();
  }

  public static DbHelper instance() {
    return Instance.dbHelper;
  }

  private DbHelper() {
  }

  // 数据库观察者集合
  private final Map<Class<?>, Set<ChangedListener>> listenerMap = new HashMap<>();

  // 获取数据库表监听者集合
  private <Model extends BaseModel> Set<ChangedListener> getListeners(Class<Model> modelClass) {
    if (listenerMap.containsKey(modelClass)) {
      return listenerMap.get(modelClass);
    } else {
      return null;
    }
  }

  // 添加监听者
  public <Model extends BaseModel> void addListener(Class<Model> modelClass,
      ChangedListener<Model> listener) {
    Set<ChangedListener> listenerSet = getListeners(modelClass);
    if (listenerSet == null) {
      listenerSet = new HashSet<>();
      listenerMap.put(modelClass, listenerSet);
    }
    listenerSet.add(listener);
  }

  // 删除一个监听者
  public <Model extends BaseModel> void removeListener(Class<Model> modelClass,
      ChangedListener<Model> listener) {
    Set<ChangedListener> listenerSet = getListeners(modelClass);
    if (listenerSet == null) {
      return;
    }
    listenerSet.remove(listener);
  }

  // 添加修改数据库操作
  public <Model extends BaseModel> void saveModel(final Class<Model> modelClass,
      final Model... models) {
    if (models == null || models.length == 0) {
      return;
    }
    DatabaseDefinition definition = FlowManager.getDatabase(AppDatabase.class);
    definition.beginTransactionAsync(new ITransaction() {
      @Override public void execute(DatabaseWrapper databaseWrapper) {
        // 执行保存
        ModelAdapter<Model> adapter = FlowManager.getModelAdapter(modelClass);
        adapter.saveAll(Arrays.asList(models));
        // 通知更改
        notifySave(modelClass, models);
      }
    }).build().execute();
  }

  // 删除数据库操作
  public <Model extends BaseModel> void deleteModel(final Class<Model> modelClass,
      final Model... models) {
    if (models == null || models.length == 0) {
      return;
    }
    DatabaseDefinition definition = FlowManager.getDatabase(AppDatabase.class);
    definition.beginTransactionAsync(new ITransaction() {
      @Override public void execute(DatabaseWrapper databaseWrapper) {
        ModelAdapter<Model> adapter = FlowManager.getModelAdapter(modelClass);
        adapter.deleteAll(Arrays.asList(models));
        // 通知删除
        notifyDelete(modelClass, models);
      }
    }).build().execute();
  }

  // 通知调用
  @SuppressWarnings("unchecked") private <Model extends BaseModel> void notifySave(
      Class<Model> modelClass, Model... models) {
    Set<ChangedListener> listenerSet = getListeners(modelClass);
    if (listenerSet != null && listenerSet.size() > 0) {
      for (ChangedListener<Model> listener : listenerSet) {
        listener.onDataSave(models);
      }
    }

    if (GroupMember.class.equals(modelClass)) {
      // 群成员变更，通知对应群信息更新
      updateGroup((GroupMember[]) models);
    } else if (Message.class.equals(modelClass)) {
      // 消息变化，通知会话列表更新
      updateSession((Message[]) models);
    }
  }

  // 删除通知
  private <Model extends BaseModel> void notifyDelete(Class<Model> modelClass, Model[] models) {

    final Set<ChangedListener> listeners = getListeners(modelClass);
    if (listeners != null && listeners.size() > 0) {
      // 通用的通知
      for (ChangedListener<Model> listener : listeners) {
        listener.onDataDelete(models);
      }
    }

    // 列外情况
    if (GroupMember.class.equals(modelClass)) {
      // 群成员变更，通知对应群信息更新
      updateGroup((GroupMember[]) models);
    } else if (Message.class.equals(modelClass)) {
      // 消息变化，通知会话列表更新
      updateSession((Message[]) models);
    }
  }

  // 群更新
  private void updateGroup(GroupMember... members) {
    // 不重复集合
    final Set<String> groupIds = new HashSet<>();
    for (GroupMember member : members) {
      // 添加群Id
      groupIds.add(member.getGroup().getId());
    }

    // 异步的数据库查询，并异步的发起二次通知
    DatabaseDefinition definition = FlowManager.getDatabase(AppDatabase.class);
    definition.beginTransactionAsync(new ITransaction() {
      @Override public void execute(DatabaseWrapper databaseWrapper) {
        // 找到需要通知的群
        List<Group> groups =
            SQLite.select().from(Group.class).where(Group_Table.id.in(groupIds)).queryList();

        // 调用直接进行一次通知分发
        notifySave(Group.class, groups.toArray(new Group[0]));
      }
    }).build().execute();
  }

  private void updateSession(Message... messages) {
    // 标示一个Session的唯一性
    final Set<Session.Identify> identifies = new HashSet<>();
    for (Message message : messages) {
      Session.Identify identify = Session.createSessionIdentify(message);
      identifies.add(identify);
    }

    // 异步的数据库查询，并异步的发起二次通知
    DatabaseDefinition definition = FlowManager.getDatabase(AppDatabase.class);
    definition.beginTransactionAsync(new ITransaction() {
      @Override public void execute(DatabaseWrapper databaseWrapper) {
        ModelAdapter<Session> adapter = FlowManager.getModelAdapter(Session.class);
        Session[] sessions = new Session[identifies.size()];

        int index = 0;
        for (Session.Identify identify : identifies) {
          Session session = SessionHelper.findFromLocal(identify.id);

          if (session == null) {
            // 第一次聊天，创建会话
            session = new Session(identify);
          }

          // 会话信息刷新
          session.refreshToNow();
          // 数据存储
          adapter.save(session);
          // 添加到集合
          sessions[index++] = session;
        }

        // 调用直接进行一次通知分发
        notifySave(Session.class, sessions);
      }
    }).build().execute();
  }

  @SuppressWarnings("unchecked") public interface ChangedListener<Data extends BaseModel> {
    void onDataSave(Data... list);

    void onDataDelete(Data... list);
  }
}
